package com.ticket.sass.admin.service;

import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ticket.sass.admin.dto.input.PageInput;
import com.ticket.sass.admin.model.LabModel;
import com.ticket.sass.admin.util.CompareUtil;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author 朱其鹏
 */
public interface BaseService<T> extends IService<T> {
    default Long countByIds(List<Long> checkIds){
        if (checkIds == null || checkIds.size() == 0){
            return 0L;
        }
        return this.count(new QueryWrapper<T>().in("id", checkIds));
    }
    
    default List<T> list(Object input) {
        // 创建 QueryWrapper 对象
        QueryWrapper<T> queryWrapper = buildQueryWrapper(this.getEntityClass(), input);
        
        // 在此根据需要添加其他查询条件
        queryWrapper.orderByDesc("id");
        
        // 调用 this.page 方法
        return this.list(queryWrapper);
    }
    
    
    default <U extends PageInput> IPage<T> iPage(U input) {
        if (Objects.isNull(input)) {
            return null;
        }
        
        // 创建 Page 对象
        Page<T> page = new Page<>(input.getPageNum(), input.getPageSize());
        
        // 创建 QueryWrapper 对象
        QueryWrapper<T> queryWrapper = buildQueryWrapper(this.getEntityClass(), input);
        
        // 在此根据需要添加其他查询条件
        queryWrapper.orderByDesc("id");
        
        // 调用 this.page 方法
        return this.page(page, queryWrapper);
    }
    
    
    default <U extends PageInput> IPage<T> iPage(Class<T> entityClass, U input) {
        if (Objects.isNull(input)) {
            return null;
        }
        
        // 创建 Page 对象
        Page<T> page = new Page<>(input.getPageNum(), input.getPageSize());
        
        // 创建 QueryWrapper 对象
        QueryWrapper<T> queryWrapper = buildQueryWrapper(entityClass, input);
        
        // 在此根据需要添加其他查询条件
        queryWrapper.orderByDesc("id");
        
        // 调用 this.page 方法
        return this.page(page, queryWrapper);
    }
    
    default Long countById(Long id){
        return this.count(new QueryWrapper<T>().eq("id", id));
    }
    
    default boolean isEmpty(Long id){
        return countById(id) <= 0;
    }
    
    default boolean isNotEmpty(Long id){
        return !isEmpty(id);
    }

    default List<T> listByIn(List<Long> ids){
        if (ids.isEmpty()){
            return new ArrayList<>();
        }
        return this.list(new QueryWrapper<T>().in("id", ids));
    }
    
    default Map<Long, T> mapByIds(List<Long> ids){
        if (ids.isEmpty()){
            return new HashMap<>();
        }
        
        // 获取实体列表
        List<T> entities = this.listByIn(ids);
        
        // 使用流式操作将实体列表转换为Map
        return entities.stream()
            .collect(Collectors.toMap(this::getIdFromEntity, entity -> entity));
    }
    
    default T findBy(Object value, String column){
        return this.getOne(new QueryWrapper<T>().eq(column, value).last("limit 1"));
    }
    
    default List<T> listBy(Object value, String column){
        return this.list(new QueryWrapper<T>().eq(column, value));
    }
    
    // 构建 QueryWrapper
    default QueryWrapper<T> buildQueryWrapper(Class<T> entityClass, Object input) {
        QueryWrapper<T> queryWrapper = new QueryWrapper<>();
        
        // 获取 T 类型的所有字段
        Field[] tFields = ReflectUtil.getFields(entityClass);
        
        // 遍历 T 类型的字段
        for (Field tField : tFields) {
            try {
                // 获取字段名称
                String fieldName = tField.getName();
                Set<String> keywords = new HashSet<>();
                keywords.add("desc");
             
                
                // 将驼峰命名转换为下划线分隔的数据库列名
                String columnName = StrUtil.toUnderlineCase(fieldName);
                if (keywords.contains(fieldName)){
                    columnName = "\"" + columnName + "\"";
                }
                
                // 根据字段名称获取 U 类型的字段
                Field uField = ReflectUtil.getField(input.getClass(), fieldName);
                
                // 如果在 U 类型中找到了相同名称的字段
                if (uField != null) {
                    // 设置字段可访问
                    ReflectUtil.setAccessible(tField);
                    ReflectUtil.setAccessible(uField);
                    
                    // 获取字段的值
                    Object value = ReflectUtil.getFieldValue(input, uField);
                    
                    // 根据字段类型添加查询条件
                    if (value != null) {
                        if (value instanceof String && StrUtil.isNotEmpty((String) value)) {
                            queryWrapper.like(true, columnName, value);
                        } else if (value instanceof Long) {
                            queryWrapper.eq(true, columnName, value);
                        } else if (value instanceof Boolean){
                            queryWrapper.eq(true, columnName, value);
                        } else if (value instanceof Short){
                            queryWrapper.eq(true, columnName, value);
                        } else if (value instanceof Integer){
                            queryWrapper.eq(true, columnName, value);
                        } else if (value instanceof BigDecimal){
                            queryWrapper.eq(true, columnName, value);
                        }
                        // 可根据需要添加其他类型的判断
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        
        return queryWrapper;
    }
    
    default List<LabModel> getLabModels(QueryWrapper<T> queryWrapper) {
        if (queryWrapper == null) {
            return null;
        }
        
        // 调用 this.list 方法获取符合条件的实体对象列表
        List<T> entityList = this.list(queryWrapper);
        
        // 创建 LabModel 列表
        List<LabModel> labModels = new ArrayList<>();
        
        // 遍历实体对象列表，填充 LabModel 对象并加入到结果列表中
        for (T entity : entityList) {
            LabModel labModel = new LabModel();
            // 获取实体对象中的 id 和 name/title 字段的值
            Long id = getIdFromEntity(entity);
            String name = getNameOrTitleFromEntity(entity);
            // 设置 LabModel 对象的 id 和 name 字段的值
            labModel.setId(id);
            labModel.setName(name);
            labModels.add(labModel);
        }
        
        return labModels;
    }
    
    
    // 获取实体对象中的 id
    default Long getIdFromEntity(T entity) {
        try {
            // 获取实体对象的类对象
            Class<?> entityClass = this.getEntityClass();
            // 通过反射获取 id 字段的值
            Field idField = entityClass.getDeclaredField("id");
            idField.setAccessible(true); // 设置字段可访问
            return (Long) idField.get(entity);
        } catch (Exception e) {
            // 异常处理
            e.printStackTrace();
            return null;
        }
    }
    
    // 获取实体对象中的 name 或 title
    default String getNameOrTitleFromEntity(T entity) {
        try {
            // 获取实体对象的类对象
            Class<?> entityClass = this.getEntityClass();
            // 先尝试获取 name 字段的值
            Field nameField = entityClass.getDeclaredField("name");
            nameField.setAccessible(true); // 设置字段可访问
            String name = (String) nameField.get(entity);
            if (name != null) {
                return name;
            }
            // 如果 name 字段不存在或者值为空，则尝试获取 title 字段的值
            Field titleField = entityClass.getDeclaredField("title");
            titleField.setAccessible(true); // 设置字段可访问
            return (String) titleField.get(entity);
        } catch (Exception e) {
            // 异常处理
            e.printStackTrace();
            return null;
        }
    }
    
    /**
     * 保存关联关系。
     *
     * @param mainId 主表的ID，例如 coupon_id
     * @param newRelatedIds 新的关联关系ID列表，例如 hall_id 列表
     * @param mainFieldName 主表ID字段名称，例如 "coupon_id"
     * @param relatedFieldName 关联表ID字段名称，例如 "hall_id"
     */
    default void saveRelations(Long mainId, List<Long> newRelatedIds, String mainFieldName, String relatedFieldName) {
        // 添加新关系
        if (!newRelatedIds.isEmpty()) {
            newRelatedIds.forEach(relatedId -> {
                T newRelation = this.createNewInstance();
                setFieldValue(newRelation, mainFieldName, mainId);
                setFieldValue(newRelation, relatedFieldName, relatedId);
                this.save(newRelation);
            });
        }
    }
    
    
    
    /**
     * 更新关联关系。
     *
     * @param mainId 主表的ID，例如 coupon_id
     * @param newRelatedIds 新的关联关系ID列表，例如 hall_id 列表
     * @param mainFieldName 主表ID字段名称，例如 "coupon_id"
     * @param relatedFieldName 关联表ID字段名称，例如 "hall_id"
     */
    default void updateRelations(Long mainId, List<Long> newRelatedIds, String mainFieldName, String relatedFieldName) {
        // 获取当前关联的相关 ID 列表
        QueryWrapper<T> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(mainFieldName, mainId);
        queryWrapper.select(relatedFieldName);
        
        // 获取当前关联的 ID 列表
        List<Long> currentRelatedIds = this.listObjs(queryWrapper, obj -> (Long) obj);
        
        CompareUtil<Long> compareUtil = new CompareUtil<>(currentRelatedIds, newRelatedIds);

        // 删除旧关系
        if (compareUtil.isDel()) {
            this.remove(new QueryWrapper<T>().eq(mainFieldName, mainId).in(relatedFieldName, compareUtil.getDel()));
        }
        
        // 添加新关系
        if (compareUtil.isInsert()) {
            compareUtil.getInsert().forEach(relatedId -> {
                T newRelation = this.createNewInstance();
                setFieldValue(newRelation, mainFieldName, mainId);
                setFieldValue(newRelation, relatedFieldName, relatedId);
                this.save(newRelation);
            });
        }
    }
    
    /**
     * 默认创建新的实体实例。
     *
     * @return 新的实体实例
     */
    default T createNewInstance() {
        try {
            // 获取 T 的无参构造函数并实例化
            return this.getEntityClass().getDeclaredConstructor().newInstance();
        } catch (InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
            throw new RuntimeException("创建新实例失败", e);
        }
    }

    
    /**
     * 默认通过反射设置实体的字段值。
     *
     * @param entity 实体对象
     * @param fieldName 字段名
     * @param value 值
     */
    default void setFieldValue(T entity, String fieldName, Object value) {
        try {
            // 根据字段名获取属性
            String propertyName = camelCase(fieldName);
            Field field = entity.getClass().getDeclaredField(propertyName);
            field.setAccessible(true);
            field.set(entity, value);
        } catch (NoSuchFieldException | IllegalAccessException e) {
            throw new RuntimeException("设置字段值失败", e);
        }
    }
    
    /**
     * 转换数据库字段名为驼峰命名。
     *
     * @param fieldName 数据库字段名
     * @return 驼峰命名的属性名
     */
    default String camelCase(String fieldName) {
        StringBuilder result = new StringBuilder();
        boolean nextUpperCase = false;
        for (char c : fieldName.toCharArray()) {
            if (c == '_') {
                nextUpperCase = true;
            } else {
                if (nextUpperCase) {
                    result.append(Character.toUpperCase(c));
                    nextUpperCase = false;
                } else {
                    result.append(c);
                }
            }
        }
        return result.toString();
    }
}
